Installing required packages

library(rtweet)
package 㤼㸱rtweet㤼㸲 was built under R version 4.0.4
library(dplyr)
library(tidyr)
library(tidytext)
package 㤼㸱tidytext㤼㸲 was built under R version 4.0.4
library(ggplot.multistats)
package 㤼㸱ggplot.multistats㤼㸲 was built under R version 4.0.4
library(ggplot2)
package 㤼㸱ggplot2㤼㸲 was built under R version 4.0.4
library(forestmangr)
package 㤼㸱forestmangr㤼㸲 was built under R version 4.0.4
Attaching package: 㤼㸱forestmangr㤼㸲

The following object is masked from 㤼㸱package:data.table㤼㸲:

    :=
library(syuzhet)
package 㤼㸱syuzhet㤼㸲 was built under R version 4.0.4
Attaching package: 㤼㸱syuzhet㤼㸲

The following object is masked from 㤼㸱package:rtweet㤼㸲:

    get_tokens
library(tidyverse)
package 㤼㸱tidyverse㤼㸲 was built under R version 4.0.4Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
-- Attaching packages ------------------------------------------------------------------------------------------------------------ tidyverse 1.3.0 --
v tibble  3.0.4     v stringr 1.4.0
v readr   1.4.0     v forcats 0.5.0
v purrr   0.3.4     
package 㤼㸱stringr㤼㸲 was built under R version 4.0.4-- Conflicts --------------------------------------------------------------------------------------------------------------- tidyverse_conflicts() --
x dplyr::between()   masks data.table::between()
x dplyr::filter()    masks stats::filter()
x dplyr::first()     masks data.table::first()
x purrr::flatten()   masks rtweet::flatten()
x dplyr::lag()       masks stats::lag()
x dplyr::last()      masks data.table::last()
x purrr::transpose() masks data.table::transpose()
library(readxl) # read excel
package 㤼㸱readxl㤼㸲 was built under R version 4.0.4
library(tibble) # tobble dataframe
library(dplyr) # piping
library(stringr) # character manipulation
library(tidytext)
library(tokenizers)
package 㤼㸱tokenizers㤼㸲 was built under R version 4.0.4
library(stopwords)
package 㤼㸱stopwords㤼㸲 was built under R version 4.0.4
library(tidyverse)
library(lobstr)
package 㤼㸱lobstr㤼㸲 was built under R version 4.0.4
library(glue)

Attaching package: 㤼㸱glue㤼㸲

The following object is masked from 㤼㸱package:dplyr㤼㸲:

    collapse
library(stringr)

Loading the data

blm2020<-read.csv('../../gen/data-preparation/temp/BLM2020_dataset.csv', sep = ' ', na.strings=c("", "NA"))

blm2021<-read.csv('../../gen/data-preparation/temp/BLM2021_dataset.csv', sep = ' ', na.strings=c("", "NA"))
EOF within quoted stringError in read.table(file = file, header = header, sep = sep, quote = quote,  : 
  duplicate 'row.names' are not allowed

Show the ratio of replies, retweets and likes

#Retweets
blm2020_retweets<-blm2020[blm2020$retweet > 1, ]
blm2020_retweets
blm2021_retweets<-blm2021[blm2021$retweet > 1, ]
blm2021_retweets
NA
#Likes
blm2020_likes<-blm2020[blm2020$like >1, ]
blm2020_likes
blm2021_likes<-blm2021[blm2021$like >1, ]
blm2021_likes
NA
#Replies
blm2020_replies<-blm2020[blm2020$reply >1, ]
blm2020_replies
blm2021_replies<-blm2021[blm2021$reply >1, ]
blm2021_replies
NA

Creating a data frame


data2020<-data.frame(category=c("Retweets", "Likes", "Replies"), count=c(2, 5, 3))
data2020
data2021<-data.frame(category=c("Retweets", "Likes", "Replies"), count=c(707, 1738, 574))
data2021

Visualizing the data 2020

#Adding columns
data2020$fraction = data2020$count / sum(data2020$count)
data2020$percentage = data2020$count / sum(data2020$count) * 100
data2020$ymax = cumsum(data2020$fraction)
data2020$ymin = c(0, head(data2020$ymax, n=-1))

#Rounding up

data2020 <- round_df(data2020, 2)

# Specify what the legend should say
Type_of_Tweet <- paste(data2020$category, data2020$percentage, "%")

ggplot(data2020, aes(ymax=ymax, ymin=ymin, xmax=4, xmin=3, fill=Type_of_Tweet)) +
  geom_rect() +
  coord_polar(theta="y") + 
  xlim(c(2, 4)) +
  theme_void() +
  theme(legend.position = "right")

Visualizing the data 2021


#Adding columns
data2021$fraction = data2021$count / sum(data2021$count)
data2021$percentage = data2021$count / sum(data2021$count) * 100
data2021$ymax = cumsum(data2021$fraction)
data2021$ymin = c(0, head(data2021$ymax, n=-1))

#Rounding up

data2021 <- round_df(data2021, 2)

# Specify what the legend should say
Type_of_Tweet <- paste(data2020$category, data2021$percentage, "%")

ggplot(data2021, aes(ymax=ymax, ymin=ymin, xmax=4, xmin=3, fill=Type_of_Tweet)) +
  geom_rect() +
  coord_polar(theta="y") + 
  xlim(c(2, 4)) +
  theme_void() +
  theme(legend.position = "right")

Most frequent words in the 2020 tweets

Lets see which words are more frequently used in the posts of 2020

blm2020$text <- gsub("@\\S*", "", blm2020$text)
blm2020$text <- gsub("amp", "", blm2020$text) 
blm2020$text <- gsub("[\r\n]", "", blm2020$text)
blm2020$text <- gsub("[[:punct:]]", "", blm2020$text)

#removing stop words from the text - so the most frequent words are not or at and

tweets <- blm2020 %>%
  select(text) %>%
  unnest_tokens(word, text)
tweets <- tweets %>%
  anti_join(get_stopwords(language = "nl", source = "snowball"))
Joining, by = "word"
#making a histogram
tweets %>% # gives you a bar chart of the most frequent words found in the tweets
  count(word, sort = TRUE) %>%
  top_n(15) %>%
  mutate(word = reorder(word, n)) %>%
  ggplot(aes(x = word, y = n)) +
  geom_col() +
  xlab(NULL) +
  coord_flip() +
  labs(y = "Count",
       x = "Unique words",
       title = "Most frequent words found in the tweets of #BLM",
       subtitle = "Stop words removed from the list")
Selecting by n

Most frequent words in the 2021 tweets Lets now see which words are more frequently used in the posts of 2021

blm2021$text <- gsub("@\\S*", "", blm2021$text)
blm2021$text <- gsub("amp", "", blm2021$text) 
blm2021$text <- gsub("[\r\n]", "", blm2021$text)
blm2021$text <- gsub("[[:punct:]]", "", blm2021$text)

#removing stop words from the text - so the most frequent words are not or at and

tweets1 <- blm2021 %>%
  select(text) %>%
  unnest_tokens(word, text)
tweets1 <- tweets1 %>%
  anti_join(get_stopwords(language = "nl", source = "snowball"))
Joining, by = "word"
#making a histogram
tweets1 %>% # gives you a bar chart of the most frequent words found in the tweets
  count(word, sort = TRUE) %>%
  top_n(15) %>%
  mutate(word = reorder(word, n)) %>%
  ggplot(aes(x = word, y = n)) +
  geom_col() +
  xlab(NULL) +
  coord_flip() +
  labs(y = "Count",
       x = "Unique words",
       title = "Most frequent words found in the tweets of #BLM 2021",
       subtitle = "Stop words removed from the list")
Selecting by n

Sentiment analysis for positive or negative tweets 2020

# Converting tweets to ASCII to trackle strange characters
tweets_sentiment <- iconv(tweets, from="UTF-8", to="ASCII", sub="")

# removing retweets, in case needed 
tweets_sentiment <-gsub("(RT|via)((?:\\b\\w*@\\w+)+)","",tweets_sentiment)

# removing mentions, in case needed
tweets_sentiment <-gsub("@\\w+","",tweets_sentiment)
ew_sentiment<-get_nrc_sentiment((tweets_sentiment))
sentimentscores<-data.frame(colSums(ew_sentiment[,]))
names(sentimentscores) <- "Score"
sentimentscores <- cbind("sentiment"=rownames(sentimentscores),sentimentscores)
rownames(sentimentscores) <- NULL
ggplot(data=sentimentscores,aes(x=sentiment,y=Score))+
  geom_bar(aes(fill=sentiment),stat = "identity")+
  theme(legend.position="none")+
  xlab("Sentiments")+ylab("Scores")+
  ggtitle("Total sentiment based on scores 2020")+
  theme_minimal()

Sentiment analysis for positive or negative tweets 2021

# Converting tweets to ASCII to trackle strange characters
tweets_sentiment_1 <- iconv(tweets, from="UTF-8", to="ASCII", sub="")

# removing retweets, in case needed 
tweets_sentiment_1 <-gsub("(RT|via)((?:\\b\\w*@\\w+)+)","",tweets_sentiment_1)

# removing mentions, in case needed
tweets_sentiment_1 <-gsub("@\\w+","",tweets_sentiment_1)
ew_sentiment<-get_nrc_sentiment((tweets_sentiment))
sentimentscores<-data.frame(colSums(ew_sentiment[,]))
names(sentimentscores) <- "Score"
sentimentscores <- cbind("sentiment"=rownames(sentimentscores),sentimentscores)
rownames(sentimentscores) <- NULL
ggplot(data=sentimentscores,aes(x=sentiment,y=Score))+
  geom_bar(aes(fill=sentiment),stat = "identity")+
  theme(legend.position="none")+
  xlab("Sentiments")+ylab("Scores")+
  ggtitle("Total sentiment based on scores 2021")+
  theme_minimal()

Visualizing the variables in the dataset 2020

#Making a ggplot
#ploting retweets by location
ggplot(data = blm2020) + 
  geom_point(mapping = aes(x = retweet, y = location))
#ploting retweets by datetime
#need to separate date from time
ggplot(data = blm2020) + 
  geom_point(mapping = aes(x = retweet, y = datetime), color = "blue")

Graphing users amount of followers and user amount friends

ggplot(data = blm2020) + 
  geom_point(mapping = aes(x = user_amount_followers, y = user_amount_friends), color = "blue")

Graphing users amount status by location To check how much users Tweet by Location

ggplot(data = blm2020) + 
  geom_point(mapping = aes(x = user_amount_status, y = location), color = "blue")

#Filter if parties are mentioned in 2020

state.name[grep ("VVD", "PvdA", "PVV", "CDA", "SP", "CU", "PvdD", state.name)]

Visualizing the variables in the dataset 2021 ####needs amendments!!!!

#Making a ggplot
#ploting retweets by location
ggplot(data = blm2021) + 
  geom_point(mapping = aes(x = retweet, y = location))

#ploting retweets by datetime
#need to separate date from time
ggplot(data = blm2021) + 
  geom_point(mapping = aes(x = retweet, y = datetime), color = "blue")

Graphing users amount of followers and user amount friends

ggplot(data = blm2021) + 
  geom_point(mapping = aes(x = user_amount_followers, y = user_amount_friends), color = "blue")

Graphing users amount status by location To check how much users Tweet by Location

ggplot(data = blm2021) + 
  geom_point(mapping = aes(x = user_amount_status, y = location), color = "blue")

#Filter if parties are mentioned in 2021

state.name[grep ("VVD", "PvdA", "PVV", "CDA", "SP", "CU", "PvdD", state.name)]
#remive dollar signs

blm2020<-gsub("\\$", "", blm2020)
blm2021<-gsub("\\$","", blm2021)

Sentiment analysis

# create a list of tokens
#https://www.kaggle.com/rtatman/tokenization-tutorial

tokens_2020<-data.frame(text= blm2020) %>% unnest_tokens(word, text)
tokens_2020
tokens_2021<-data.frame(text=blm2021) %>% unnest_tokens(word, text)
tokens_2021

Now that we have a list of tokens, we need to compare them against a list of words with either positive or negative sentiment.

# get the sentiment from the first text: 
tokens_2020 %>%
  inner_join(get_sentiments("bing")) %>% # pull out only sentiment words
  count(sentiment) %>% # count the # of positive & negative words
  spread(sentiment, n, fill = 0) %>% # made data wide rather than narrow
  mutate(sentiment = positive - negative) # # of positive words - # of negative words
Joining, by = "word"
#do the same for 2021

tokens_2021 %>%
  inner_join(get_sentiments("bing")) %>% # pull out only sentiment words
  count(sentiment) %>% # count the # of positive & negative words
  spread(sentiment, n, fill = 0) %>% # made data wide rather than narrow
  mutate(sentiment = positive - negative) # # of positive words - # of negative words
Joining, by = "word"
blm2020$sentiment<-get_sentiment(blm2020$text)
Error in blm2020$text : $ operator is invalid for atomic vectors

Now we will perform an ANOVA with DV the sentiment of the text and control variablw the source of the tweet

https://www.scribbr.com/statistics/anova-in-r/

#2020
one.way_2020 <- aov(sentiment ~ source_tweet , data = blm2020)
Error in model.frame.default(formula = sentiment ~ source_tweet, data = blm2020,  : 
  'data' must be a data.frame, environment, or list
#2021

one.way_2021 <- aov(sentiment ~ source_tweet, data = blm2021)
Error in model.frame.default(formula = sentiment ~ source_tweet, data = blm2021,  : 
  'data' must be a data.frame, environment, or list

#How can we measure how many tweets are made by location?

references: 1. https://towardsdatascience.com/a-guide-to-mining-and-analysing-tweets-with-r-2f56818fdd16 2. https://ourcodingclub.github.io/tutorials/time/ 3. https://cran.r-project.org/web/packages/stopwords/stopwords.pdf 4. https://www.dummies.com/programming/r/how-to-search-for-individual-words-in-r/ 5. https://r4ds.had.co.nz/data-visualisation.html 6. Anova and sentiment analysis: https://www.kaggle.com/rtatman/tutorial-sentiment-analysis-in-r

sum(""(BLM2020))
sum(is.na(BLM2020$Datetime))
sum(is.na(BLM2020$Text))
sum(is.na(BLM2020$Tweet.Id))
sum(is.na(BLM2020$Username))
sum(is.na(BLM2020$Location))
sum(is.na(BLM2020$Location))
summary(BLM2020)
summary(BLM2020$Location)

regression retweets

retweets_glm <-glm(Retweet ~ ., data=BLM2020)
Error in is.data.frame(data) : object 'BLM2020' not found

One way ANOVA

#removing html tags from the source_tweet variable

library(textclean)
html_tags <- c(
    "<bold>Random</bold> text with symbols: &nbsp; &lt; &gt; &amp; &quot; &apos;",
    "<p>More text</p> &cent; &pound; &yen; &euro; &copy; &reg;"
)

blm2020$source_tweet<- replace_html(blm2020$source_tweet)
Error in blm2020$source_tweet : $ operator is invalid for atomic vectors

running the test

#creating a 

one.way <- aov(source_tweet ~ ., data = blm2020)
Error in terms.formula(formula, "Error", data = data) : 
  '.' in formula and no 'data' argument

#Graphs for every variable #Graph on user ammount of followers #Check if a user has made multiple tweets - how can we do that? #Filter if parties are mentioned

LS0tDQp0aXRsZTogIkJMTSBkYXRhIGFuYWx5c2lzIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KKkluc3RhbGxpbmcgcmVxdWlyZWQgcGFja2FnZXMqDQoNCmBgYHtyfQ0KbGlicmFyeShydHdlZXQpDQpsaWJyYXJ5KGRwbHlyKQ0KbGlicmFyeSh0aWR5cikNCmxpYnJhcnkodGlkeXRleHQpDQpsaWJyYXJ5KGdncGxvdC5tdWx0aXN0YXRzKQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShmb3Jlc3RtYW5ncikNCmxpYnJhcnkoc3l1emhldCkNCmxpYnJhcnkodGlkeXZlcnNlKQ0KbGlicmFyeShyZWFkeGwpICMgcmVhZCBleGNlbA0KbGlicmFyeSh0aWJibGUpICMgdG9iYmxlIGRhdGFmcmFtZQ0KbGlicmFyeShkcGx5cikgIyBwaXBpbmcNCmxpYnJhcnkoc3RyaW5ncikgIyBjaGFyYWN0ZXIgbWFuaXB1bGF0aW9uDQpsaWJyYXJ5KHRpZHl0ZXh0KQ0KbGlicmFyeSh0b2tlbml6ZXJzKQ0KbGlicmFyeShzdG9wd29yZHMpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkobG9ic3RyKQ0KbGlicmFyeShnbHVlKQ0KbGlicmFyeShzdHJpbmdyKQ0KDQpgYGANCipMb2FkaW5nIHRoZSBkYXRhKg0KDQpgYGB7cn0NCmJsbTIwMjA8LXJlYWQuY3N2KCcuLi8uLi9nZW4vZGF0YS1wcmVwYXJhdGlvbi90ZW1wL0JMTTIwMjBfZGF0YXNldC5jc3YnLCBzZXAgPSAnICcsIG5hLnN0cmluZ3M9YygiIiwgIk5BIikpDQoNCmJsbTIwMjE8LXJlYWQuY3N2KCcuLi8uLi9nZW4vZGF0YS1wcmVwYXJhdGlvbi90ZW1wL0JMTTIwMjFfZGF0YXNldC5jc3YnLCBzZXAgPSAnJywgbmEuc3RyaW5ncz1jKCIiLCAiTkEiKSkNCmBgYA0KDQoNCipTaG93IHRoZSByYXRpbyBvZiByZXBsaWVzLCByZXR3ZWV0cyBhbmQgbGlrZXMqDQoNCmBgYHtyfQ0KI1JldHdlZXRzDQpibG0yMDIwX3JldHdlZXRzPC1ibG0yMDIwW2JsbTIwMjAkcmV0d2VldCA+IDEsIF0NCmJsbTIwMjBfcmV0d2VldHMNCmJsbTIwMjFfcmV0d2VldHM8LWJsbTIwMjFbYmxtMjAyMSRyZXR3ZWV0ID4gMSwgXQ0KYmxtMjAyMV9yZXR3ZWV0cw0KDQpgYGANCg0KYGBge3J9DQojTGlrZXMNCmJsbTIwMjBfbGlrZXM8LWJsbTIwMjBbYmxtMjAyMCRsaWtlID4xLCBdDQpibG0yMDIwX2xpa2VzDQpibG0yMDIxX2xpa2VzPC1ibG0yMDIxW2JsbTIwMjEkbGlrZSA+MSwgXQ0KYmxtMjAyMV9saWtlcw0KDQpgYGANCg0KDQpgYGB7cn0NCiNSZXBsaWVzDQpibG0yMDIwX3JlcGxpZXM8LWJsbTIwMjBbYmxtMjAyMCRyZXBseSA+MSwgXQ0KYmxtMjAyMF9yZXBsaWVzDQpibG0yMDIxX3JlcGxpZXM8LWJsbTIwMjFbYmxtMjAyMSRyZXBseSA+MSwgXQ0KYmxtMjAyMV9yZXBsaWVzDQoNCmBgYA0KKkNyZWF0aW5nIGEgZGF0YSBmcmFtZSoNCg0KYGBge3J9DQoNCmRhdGEyMDIwPC1kYXRhLmZyYW1lKGNhdGVnb3J5PWMoIlJldHdlZXRzIiwgIkxpa2VzIiwgIlJlcGxpZXMiKSwgY291bnQ9YygyLCA1LCAzKSkNCmRhdGEyMDIwDQpkYXRhMjAyMTwtZGF0YS5mcmFtZShjYXRlZ29yeT1jKCJSZXR3ZWV0cyIsICJMaWtlcyIsICJSZXBsaWVzIiksIGNvdW50PWMoNzA3LCAxNzM4LCA1NzQpKQ0KZGF0YTIwMjENCmBgYA0KDQoqVmlzdWFsaXppbmcgdGhlIGRhdGEgMjAyMCoNCg0KYGBge3J9DQojQWRkaW5nIGNvbHVtbnMNCmRhdGEyMDIwJGZyYWN0aW9uID0gZGF0YTIwMjAkY291bnQgLyBzdW0oZGF0YTIwMjAkY291bnQpDQpkYXRhMjAyMCRwZXJjZW50YWdlID0gZGF0YTIwMjAkY291bnQgLyBzdW0oZGF0YTIwMjAkY291bnQpICogMTAwDQpkYXRhMjAyMCR5bWF4ID0gY3Vtc3VtKGRhdGEyMDIwJGZyYWN0aW9uKQ0KZGF0YTIwMjAkeW1pbiA9IGMoMCwgaGVhZChkYXRhMjAyMCR5bWF4LCBuPS0xKSkNCg0KI1JvdW5kaW5nIHVwDQoNCmRhdGEyMDIwIDwtIHJvdW5kX2RmKGRhdGEyMDIwLCAyKQ0KDQojIFNwZWNpZnkgd2hhdCB0aGUgbGVnZW5kIHNob3VsZCBzYXkNClR5cGVfb2ZfVHdlZXQgPC0gcGFzdGUoZGF0YTIwMjAkY2F0ZWdvcnksIGRhdGEyMDIwJHBlcmNlbnRhZ2UsICIlIikNCg0KZ2dwbG90KGRhdGEyMDIwLCBhZXMoeW1heD15bWF4LCB5bWluPXltaW4sIHhtYXg9NCwgeG1pbj0zLCBmaWxsPVR5cGVfb2ZfVHdlZXQpKSArDQogIGdlb21fcmVjdCgpICsNCiAgY29vcmRfcG9sYXIodGhldGE9InkiKSArIA0KICB4bGltKGMoMiwgNCkpICsNCiAgdGhlbWVfdm9pZCgpICsNCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInJpZ2h0IikNCg0KYGBgDQoqVmlzdWFsaXppbmcgdGhlIGRhdGEgMjAyMSoNCg0KYGBge3J9DQoNCiNBZGRpbmcgY29sdW1ucw0KZGF0YTIwMjEkZnJhY3Rpb24gPSBkYXRhMjAyMSRjb3VudCAvIHN1bShkYXRhMjAyMSRjb3VudCkNCmRhdGEyMDIxJHBlcmNlbnRhZ2UgPSBkYXRhMjAyMSRjb3VudCAvIHN1bShkYXRhMjAyMSRjb3VudCkgKiAxMDANCmRhdGEyMDIxJHltYXggPSBjdW1zdW0oZGF0YTIwMjEkZnJhY3Rpb24pDQpkYXRhMjAyMSR5bWluID0gYygwLCBoZWFkKGRhdGEyMDIxJHltYXgsIG49LTEpKQ0KDQojUm91bmRpbmcgdXANCg0KZGF0YTIwMjEgPC0gcm91bmRfZGYoZGF0YTIwMjEsIDIpDQoNCiMgU3BlY2lmeSB3aGF0IHRoZSBsZWdlbmQgc2hvdWxkIHNheQ0KVHlwZV9vZl9Ud2VldCA8LSBwYXN0ZShkYXRhMjAyMCRjYXRlZ29yeSwgZGF0YTIwMjEkcGVyY2VudGFnZSwgIiUiKQ0KDQpnZ3Bsb3QoZGF0YTIwMjEsIGFlcyh5bWF4PXltYXgsIHltaW49eW1pbiwgeG1heD00LCB4bWluPTMsIGZpbGw9VHlwZV9vZl9Ud2VldCkpICsNCiAgZ2VvbV9yZWN0KCkgKw0KICBjb29yZF9wb2xhcih0aGV0YT0ieSIpICsgDQogIHhsaW0oYygyLCA0KSkgKw0KICB0aGVtZV92b2lkKCkgKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAicmlnaHQiKQ0KDQpgYGANCg0KDQoNCg0KKk1vc3QgZnJlcXVlbnQgd29yZHMgaW4gdGhlIDIwMjAgdHdlZXRzKg0KDQpMZXRzIHNlZSB3aGljaCB3b3JkcyBhcmUgbW9yZSBmcmVxdWVudGx5IHVzZWQgaW4gdGhlIHBvc3RzIG9mIDIwMjANCg0KYGBge3J9DQpibG0yMDIwJHRleHQgPC0gZ3N1YigiQFxcUyoiLCAiIiwgYmxtMjAyMCR0ZXh0KQ0KYmxtMjAyMCR0ZXh0IDwtIGdzdWIoImFtcCIsICIiLCBibG0yMDIwJHRleHQpIA0KYmxtMjAyMCR0ZXh0IDwtIGdzdWIoIltcclxuXSIsICIiLCBibG0yMDIwJHRleHQpDQpibG0yMDIwJHRleHQgPC0gZ3N1YigiW1s6cHVuY3Q6XV0iLCAiIiwgYmxtMjAyMCR0ZXh0KQ0KDQpgYGANCg0KDQpgYGB7cn0NCg0KI3JlbW92aW5nIHN0b3Agd29yZHMgZnJvbSB0aGUgdGV4dCAtIHNvIHRoZSBtb3N0IGZyZXF1ZW50IHdvcmRzIGFyZSBub3Qgb3IgYXQgYW5kDQoNCnR3ZWV0cyA8LSBibG0yMDIwICU+JQ0KICBzZWxlY3QodGV4dCkgJT4lDQogIHVubmVzdF90b2tlbnMod29yZCwgdGV4dCkNCnR3ZWV0cyA8LSB0d2VldHMgJT4lDQogIGFudGlfam9pbihnZXRfc3RvcHdvcmRzKGxhbmd1YWdlID0gIm5sIiwgc291cmNlID0gInNub3diYWxsIikpDQoNCmBgYA0KDQpgYGB7cn0NCiNtYWtpbmcgYSBoaXN0b2dyYW0NCnR3ZWV0cyAlPiUgIyBnaXZlcyB5b3UgYSBiYXIgY2hhcnQgb2YgdGhlIG1vc3QgZnJlcXVlbnQgd29yZHMgZm91bmQgaW4gdGhlIHR3ZWV0cw0KICBjb3VudCh3b3JkLCBzb3J0ID0gVFJVRSkgJT4lDQogIHRvcF9uKDE1KSAlPiUNCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAlPiUNCiAgZ2dwbG90KGFlcyh4ID0gd29yZCwgeSA9IG4pKSArDQogIGdlb21fY29sKCkgKw0KICB4bGFiKE5VTEwpICsNCiAgY29vcmRfZmxpcCgpICsNCiAgbGFicyh5ID0gIkNvdW50IiwNCiAgICAgICB4ID0gIlVuaXF1ZSB3b3JkcyIsDQogICAgICAgdGl0bGUgPSAiTW9zdCBmcmVxdWVudCB3b3JkcyBmb3VuZCBpbiB0aGUgdHdlZXRzIG9mICNCTE0iLA0KICAgICAgIHN1YnRpdGxlID0gIlN0b3Agd29yZHMgcmVtb3ZlZCBmcm9tIHRoZSBsaXN0IikNCmBgYA0KKk1vc3QgZnJlcXVlbnQgd29yZHMgaW4gdGhlIDIwMjEgdHdlZXRzKg0KTGV0cyBub3cgc2VlIHdoaWNoIHdvcmRzIGFyZSBtb3JlIGZyZXF1ZW50bHkgdXNlZCBpbiB0aGUgcG9zdHMgb2YgMjAyMSANCg0KYGBge3J9DQpibG0yMDIxJHRleHQgPC0gZ3N1YigiQFxcUyoiLCAiIiwgYmxtMjAyMSR0ZXh0KQ0KYmxtMjAyMSR0ZXh0IDwtIGdzdWIoImFtcCIsICIiLCBibG0yMDIxJHRleHQpIA0KYmxtMjAyMSR0ZXh0IDwtIGdzdWIoIltcclxuXSIsICIiLCBibG0yMDIxJHRleHQpDQpibG0yMDIxJHRleHQgPC0gZ3N1YigiW1s6cHVuY3Q6XV0iLCAiIiwgYmxtMjAyMSR0ZXh0KQ0KDQpgYGANCg0KDQpgYGB7cn0NCg0KI3JlbW92aW5nIHN0b3Agd29yZHMgZnJvbSB0aGUgdGV4dCAtIHNvIHRoZSBtb3N0IGZyZXF1ZW50IHdvcmRzIGFyZSBub3Qgb3IgYXQgYW5kDQoNCnR3ZWV0czEgPC0gYmxtMjAyMSAlPiUNCiAgc2VsZWN0KHRleHQpICU+JQ0KICB1bm5lc3RfdG9rZW5zKHdvcmQsIHRleHQpDQp0d2VldHMxIDwtIHR3ZWV0czEgJT4lDQogIGFudGlfam9pbihnZXRfc3RvcHdvcmRzKGxhbmd1YWdlID0gIm5sIiwgc291cmNlID0gInNub3diYWxsIikpDQoNCmBgYA0KDQpgYGB7cn0NCiNtYWtpbmcgYSBoaXN0b2dyYW0NCnR3ZWV0czEgJT4lICMgZ2l2ZXMgeW91IGEgYmFyIGNoYXJ0IG9mIHRoZSBtb3N0IGZyZXF1ZW50IHdvcmRzIGZvdW5kIGluIHRoZSB0d2VldHMNCiAgY291bnQod29yZCwgc29ydCA9IFRSVUUpICU+JQ0KICB0b3BfbigxNSkgJT4lDQogIG11dGF0ZSh3b3JkID0gcmVvcmRlcih3b3JkLCBuKSkgJT4lDQogIGdncGxvdChhZXMoeCA9IHdvcmQsIHkgPSBuKSkgKw0KICBnZW9tX2NvbCgpICsNCiAgeGxhYihOVUxMKSArDQogIGNvb3JkX2ZsaXAoKSArDQogIGxhYnMoeSA9ICJDb3VudCIsDQogICAgICAgeCA9ICJVbmlxdWUgd29yZHMiLA0KICAgICAgIHRpdGxlID0gIk1vc3QgZnJlcXVlbnQgd29yZHMgZm91bmQgaW4gdGhlIHR3ZWV0cyBvZiAjQkxNIDIwMjEiLA0KICAgICAgIHN1YnRpdGxlID0gIlN0b3Agd29yZHMgcmVtb3ZlZCBmcm9tIHRoZSBsaXN0IikNCmBgYA0KDQoqU2VudGltZW50IGFuYWx5c2lzIGZvciBwb3NpdGl2ZSBvciBuZWdhdGl2ZSB0d2VldHMgMjAyMCoNCg0KYGBge3J9DQojIENvbnZlcnRpbmcgdHdlZXRzIHRvIEFTQ0lJIHRvIHRyYWNrbGUgc3RyYW5nZSBjaGFyYWN0ZXJzDQp0d2VldHNfc2VudGltZW50IDwtIGljb252KHR3ZWV0cywgZnJvbT0iVVRGLTgiLCB0bz0iQVNDSUkiLCBzdWI9IiIpDQoNCiMgcmVtb3ZpbmcgcmV0d2VldHMsIGluIGNhc2UgbmVlZGVkIA0KdHdlZXRzX3NlbnRpbWVudCA8LWdzdWIoIihSVHx2aWEpKCg/OlxcYlxcdypAXFx3KykrKSIsIiIsdHdlZXRzX3NlbnRpbWVudCkNCg0KIyByZW1vdmluZyBtZW50aW9ucywgaW4gY2FzZSBuZWVkZWQNCnR3ZWV0c19zZW50aW1lbnQgPC1nc3ViKCJAXFx3KyIsIiIsdHdlZXRzX3NlbnRpbWVudCkNCmV3X3NlbnRpbWVudDwtZ2V0X25yY19zZW50aW1lbnQoKHR3ZWV0c19zZW50aW1lbnQpKQ0Kc2VudGltZW50c2NvcmVzPC1kYXRhLmZyYW1lKGNvbFN1bXMoZXdfc2VudGltZW50WyxdKSkNCm5hbWVzKHNlbnRpbWVudHNjb3JlcykgPC0gIlNjb3JlIg0Kc2VudGltZW50c2NvcmVzIDwtIGNiaW5kKCJzZW50aW1lbnQiPXJvd25hbWVzKHNlbnRpbWVudHNjb3Jlcyksc2VudGltZW50c2NvcmVzKQ0Kcm93bmFtZXMoc2VudGltZW50c2NvcmVzKSA8LSBOVUxMDQpnZ3Bsb3QoZGF0YT1zZW50aW1lbnRzY29yZXMsYWVzKHg9c2VudGltZW50LHk9U2NvcmUpKSsNCiAgZ2VvbV9iYXIoYWVzKGZpbGw9c2VudGltZW50KSxzdGF0ID0gImlkZW50aXR5IikrDQogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpKw0KICB4bGFiKCJTZW50aW1lbnRzIikreWxhYigiU2NvcmVzIikrDQogIGdndGl0bGUoIlRvdGFsIHNlbnRpbWVudCBiYXNlZCBvbiBzY29yZXMgMjAyMCIpKw0KICB0aGVtZV9taW5pbWFsKCkNCg0KYGBgDQoqU2VudGltZW50IGFuYWx5c2lzIGZvciBwb3NpdGl2ZSBvciBuZWdhdGl2ZSB0d2VldHMgMjAyMSoNCg0KYGBge3J9DQojIENvbnZlcnRpbmcgdHdlZXRzIHRvIEFTQ0lJIHRvIHRyYWNrbGUgc3RyYW5nZSBjaGFyYWN0ZXJzDQp0d2VldHNfc2VudGltZW50XzEgPC0gaWNvbnYodHdlZXRzLCBmcm9tPSJVVEYtOCIsIHRvPSJBU0NJSSIsIHN1Yj0iIikNCg0KIyByZW1vdmluZyByZXR3ZWV0cywgaW4gY2FzZSBuZWVkZWQgDQp0d2VldHNfc2VudGltZW50XzEgPC1nc3ViKCIoUlR8dmlhKSgoPzpcXGJcXHcqQFxcdyspKykiLCIiLHR3ZWV0c19zZW50aW1lbnRfMSkNCg0KIyByZW1vdmluZyBtZW50aW9ucywgaW4gY2FzZSBuZWVkZWQNCnR3ZWV0c19zZW50aW1lbnRfMSA8LWdzdWIoIkBcXHcrIiwiIix0d2VldHNfc2VudGltZW50XzEpDQpld19zZW50aW1lbnQ8LWdldF9ucmNfc2VudGltZW50KCh0d2VldHNfc2VudGltZW50KSkNCnNlbnRpbWVudHNjb3JlczwtZGF0YS5mcmFtZShjb2xTdW1zKGV3X3NlbnRpbWVudFssXSkpDQpuYW1lcyhzZW50aW1lbnRzY29yZXMpIDwtICJTY29yZSINCnNlbnRpbWVudHNjb3JlcyA8LSBjYmluZCgic2VudGltZW50Ij1yb3duYW1lcyhzZW50aW1lbnRzY29yZXMpLHNlbnRpbWVudHNjb3JlcykNCnJvd25hbWVzKHNlbnRpbWVudHNjb3JlcykgPC0gTlVMTA0KZ2dwbG90KGRhdGE9c2VudGltZW50c2NvcmVzLGFlcyh4PXNlbnRpbWVudCx5PVNjb3JlKSkrDQogIGdlb21fYmFyKGFlcyhmaWxsPXNlbnRpbWVudCksc3RhdCA9ICJpZGVudGl0eSIpKw0KICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSsNCiAgeGxhYigiU2VudGltZW50cyIpK3lsYWIoIlNjb3JlcyIpKw0KICBnZ3RpdGxlKCJUb3RhbCBzZW50aW1lbnQgYmFzZWQgb24gc2NvcmVzIDIwMjEiKSsNCiAgdGhlbWVfbWluaW1hbCgpDQoNCmBgYA0KDQoNCg0KKlZpc3VhbGl6aW5nIHRoZSB2YXJpYWJsZXMgaW4gdGhlIGRhdGFzZXQgMjAyMCoNCg0KYGBge3J9DQojTWFraW5nIGEgZ2dwbG90DQojcGxvdGluZyByZXR3ZWV0cyBieSBsb2NhdGlvbg0KZ2dwbG90KGRhdGEgPSBibG0yMDIwKSArIA0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IHJldHdlZXQsIHkgPSBsb2NhdGlvbikpDQpgYGANCmBgYHtyfQ0KI3Bsb3RpbmcgcmV0d2VldHMgYnkgZGF0ZXRpbWUNCiNuZWVkIHRvIHNlcGFyYXRlIGRhdGUgZnJvbSB0aW1lDQpnZ3Bsb3QoZGF0YSA9IGJsbTIwMjApICsgDQogIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4ID0gcmV0d2VldCwgeSA9IGRhdGV0aW1lKSwgY29sb3IgPSAiYmx1ZSIpDQoNCmBgYA0KKkdyYXBoaW5nIHVzZXJzIGFtb3VudCBvZiBmb2xsb3dlcnMgYW5kIHVzZXIgYW1vdW50IGZyaWVuZHMqDQoNCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBibG0yMDIwKSArIA0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IHVzZXJfYW1vdW50X2ZvbGxvd2VycywgeSA9IHVzZXJfYW1vdW50X2ZyaWVuZHMpLCBjb2xvciA9ICJibHVlIikNCg0KYGBgDQoNCipHcmFwaGluZyB1c2VycyBhbW91bnQgc3RhdHVzIGJ5IGxvY2F0aW9uKg0KVG8gY2hlY2sgaG93IG11Y2ggdXNlcnMgVHdlZXQgYnkgTG9jYXRpb24NCmBgYHtyfQ0KZ2dwbG90KGRhdGEgPSBibG0yMDIwKSArIA0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IHVzZXJfYW1vdW50X3N0YXR1cywgeSA9IGxvY2F0aW9uKSwgY29sb3IgPSAiYmx1ZSIpDQpgYGANCiNGaWx0ZXIgaWYgcGFydGllcyBhcmUgbWVudGlvbmVkIGluIDIwMjANCg0KYGBge3J9DQpzdGF0ZS5uYW1lW2dyZXAgKCJWVkQiLCAiUHZkQSIsICJQVlYiLCAiQ0RBIiwgIlNQIiwgIkNVIiwgIlB2ZEQiLCBzdGF0ZS5uYW1lKV0NCmBgYA0KDQoNCipWaXN1YWxpemluZyB0aGUgdmFyaWFibGVzIGluIHRoZSBkYXRhc2V0IDIwMjEqDQojIyMjbmVlZHMgYW1lbmRtZW50cyEhISENCmBgYHtyfQ0KI01ha2luZyBhIGdncGxvdA0KI3Bsb3RpbmcgcmV0d2VldHMgYnkgbG9jYXRpb24NCmdncGxvdChkYXRhID0gYmxtMjAyMSkgKyANCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSByZXR3ZWV0LCB5ID0gbG9jYXRpb24pKQ0KYGBgDQpgYGB7cn0NCiNwbG90aW5nIHJldHdlZXRzIGJ5IGRhdGV0aW1lDQojbmVlZCB0byBzZXBhcmF0ZSBkYXRlIGZyb20gdGltZQ0KZ2dwbG90KGRhdGEgPSBibG0yMDIxKSArIA0KICBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeCA9IHJldHdlZXQsIHkgPSBkYXRldGltZSksIGNvbG9yID0gImJsdWUiKQ0KDQpgYGANCipHcmFwaGluZyB1c2VycyBhbW91bnQgb2YgZm9sbG93ZXJzIGFuZCB1c2VyIGFtb3VudCBmcmllbmRzKg0KDQpgYGB7cn0NCmdncGxvdChkYXRhID0gYmxtMjAyMSkgKyANCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSB1c2VyX2Ftb3VudF9mb2xsb3dlcnMsIHkgPSB1c2VyX2Ftb3VudF9mcmllbmRzKSwgY29sb3IgPSAiYmx1ZSIpDQoNCmBgYA0KDQoqR3JhcGhpbmcgdXNlcnMgYW1vdW50IHN0YXR1cyBieSBsb2NhdGlvbioNClRvIGNoZWNrIGhvdyBtdWNoIHVzZXJzIFR3ZWV0IGJ5IExvY2F0aW9uDQpgYGB7cn0NCmdncGxvdChkYXRhID0gYmxtMjAyMSkgKyANCiAgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHggPSB1c2VyX2Ftb3VudF9zdGF0dXMsIHkgPSBsb2NhdGlvbiksIGNvbG9yID0gImJsdWUiKQ0KYGBgDQojRmlsdGVyIGlmIHBhcnRpZXMgYXJlIG1lbnRpb25lZCBpbiAyMDIxDQoNCmBgYHtyfQ0Kc3RhdGUubmFtZVtncmVwICgiVlZEIiwgIlB2ZEEiLCAiUFZWIiwgIkNEQSIsICJTUCIsICJDVSIsICJQdmREIiwgc3RhdGUubmFtZSldDQpgYGANCg0KYGBge3J9DQojcmVtaXZlIGRvbGxhciBzaWducw0KDQpibG0yMDIwPC1nc3ViKCJcXCQiLCAiIiwgYmxtMjAyMCkNCmJsbTIwMjE8LWdzdWIoIlxcJCIsIiIsIGJsbTIwMjEpDQoNCmBgYA0KDQoqU2VudGltZW50IGFuYWx5c2lzKg0KDQpgYGB7cn0NCiMgY3JlYXRlIGEgbGlzdCBvZiB0b2tlbnMNCiNodHRwczovL3d3dy5rYWdnbGUuY29tL3J0YXRtYW4vdG9rZW5pemF0aW9uLXR1dG9yaWFsDQoNCnRva2Vuc18yMDIwPC1kYXRhLmZyYW1lKHRleHQ9IGJsbTIwMjApICU+JSB1bm5lc3RfdG9rZW5zKHdvcmQsIHRleHQpDQp0b2tlbnNfMjAyMA0KdG9rZW5zXzIwMjE8LWRhdGEuZnJhbWUodGV4dD1ibG0yMDIxKSAlPiUgdW5uZXN0X3Rva2Vucyh3b3JkLCB0ZXh0KQ0KdG9rZW5zXzIwMjENCmBgYA0KDQpOb3cgdGhhdCB3ZSBoYXZlIGEgbGlzdCBvZiB0b2tlbnMsIHdlIG5lZWQgdG8gY29tcGFyZSB0aGVtIGFnYWluc3QgYSBsaXN0IG9mIHdvcmRzIHdpdGggZWl0aGVyIHBvc2l0aXZlIG9yIG5lZ2F0aXZlIHNlbnRpbWVudC4NCg0KYGBge3J9DQojIGdldCB0aGUgc2VudGltZW50IGZyb20gdGhlIGZpcnN0IHRleHQ6IA0KdG9rZW5zXzIwMjAgJT4lDQogIGlubmVyX2pvaW4oZ2V0X3NlbnRpbWVudHMoImJpbmciKSkgJT4lICMgcHVsbCBvdXQgb25seSBzZW50aW1lbnQgd29yZHMNCiAgY291bnQoc2VudGltZW50KSAlPiUgIyBjb3VudCB0aGUgIyBvZiBwb3NpdGl2ZSAmIG5lZ2F0aXZlIHdvcmRzDQogIHNwcmVhZChzZW50aW1lbnQsIG4sIGZpbGwgPSAwKSAlPiUgIyBtYWRlIGRhdGEgd2lkZSByYXRoZXIgdGhhbiBuYXJyb3cNCiAgbXV0YXRlKHNlbnRpbWVudCA9IHBvc2l0aXZlIC0gbmVnYXRpdmUpICMgIyBvZiBwb3NpdGl2ZSB3b3JkcyAtICMgb2YgbmVnYXRpdmUgd29yZHMNCg0KYGBgDQpgYGB7cn0NCiNkbyB0aGUgc2FtZSBmb3IgMjAyMQ0KDQp0b2tlbnNfMjAyMSAlPiUNCiAgaW5uZXJfam9pbihnZXRfc2VudGltZW50cygiYmluZyIpKSAlPiUgIyBwdWxsIG91dCBvbmx5IHNlbnRpbWVudCB3b3Jkcw0KICBjb3VudChzZW50aW1lbnQpICU+JSAjIGNvdW50IHRoZSAjIG9mIHBvc2l0aXZlICYgbmVnYXRpdmUgd29yZHMNCiAgc3ByZWFkKHNlbnRpbWVudCwgbiwgZmlsbCA9IDApICU+JSAjIG1hZGUgZGF0YSB3aWRlIHJhdGhlciB0aGFuIG5hcnJvdw0KICBtdXRhdGUoc2VudGltZW50ID0gcG9zaXRpdmUgLSBuZWdhdGl2ZSkgIyAjIG9mIHBvc2l0aXZlIHdvcmRzIC0gIyBvZiBuZWdhdGl2ZSB3b3Jkcw0KDQpgYGANCg0KDQpgYGB7cn0NCmJsbTIwMjAkc2VudGltZW50PC1nZXRfc2VudGltZW50KGJsbTIwMjAkdGV4dCkNCmJsbTIwMjEkc2VudGltZW50PC1nZXRfc2VudGltZW50KGJsbTIwMjEkdGV4dCkNCg0KYGBgDQoNCk5vdyB3ZSB3aWxsIHBlcmZvcm0gYW4gQU5PVkEgd2l0aCBEViB0aGUgc2VudGltZW50IG9mIHRoZSB0ZXh0IGFuZCBjb250cm9sIHZhcmlhYmx3IHRoZSBzb3VyY2Ugb2YgdGhlIHR3ZWV0DQoNCmh0dHBzOi8vd3d3LnNjcmliYnIuY29tL3N0YXRpc3RpY3MvYW5vdmEtaW4tci8NCg0KYGBge3J9DQojMjAyMA0Kb25lLndheV8yMDIwIDwtIGFvdihzZW50aW1lbnQgfiBzb3VyY2VfdHdlZXQgLCBkYXRhID0gYmxtMjAyMCkNCg0Kc3VtbWFyeShvbmUud2F5XzIwMjApDQpgYGANCmBgYHtyfQ0KIzIwMjENCg0Kb25lLndheV8yMDIxIDwtIGFvdihzZW50aW1lbnQgfiBzb3VyY2VfdHdlZXQsIGRhdGEgPSBibG0yMDIxKQ0KDQpzdW1tYXJ5KG9uZS53YXlfMjAyMSkNCg0KDQpgYGANCg0KDQoNCiNIb3cgY2FuIHdlIG1lYXN1cmUgaG93IG1hbnkgdHdlZXRzIGFyZSBtYWRlIGJ5IGxvY2F0aW9uPw0KDQpyZWZlcmVuY2VzOg0KMS4gaHR0cHM6Ly90b3dhcmRzZGF0YXNjaWVuY2UuY29tL2EtZ3VpZGUtdG8tbWluaW5nLWFuZC1hbmFseXNpbmctdHdlZXRzLXdpdGgtci0yZjU2ODE4ZmRkMTYNCjIuIGh0dHBzOi8vb3VyY29kaW5nY2x1Yi5naXRodWIuaW8vdHV0b3JpYWxzL3RpbWUvDQozLiBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMvc3RvcHdvcmRzL3N0b3B3b3Jkcy5wZGYNCjQuIGh0dHBzOi8vd3d3LmR1bW1pZXMuY29tL3Byb2dyYW1taW5nL3IvaG93LXRvLXNlYXJjaC1mb3ItaW5kaXZpZHVhbC13b3Jkcy1pbi1yLw0KNS4gaHR0cHM6Ly9yNGRzLmhhZC5jby5uei9kYXRhLXZpc3VhbGlzYXRpb24uaHRtbA0KNi4gQW5vdmEgYW5kIHNlbnRpbWVudCBhbmFseXNpczogaHR0cHM6Ly93d3cua2FnZ2xlLmNvbS9ydGF0bWFuL3R1dG9yaWFsLXNlbnRpbWVudC1hbmFseXNpcy1pbi1yDQpgYGB7cn0NCnN1bSgiIihCTE0yMDIwKSkNCnN1bShpcy5uYShCTE0yMDIwJERhdGV0aW1lKSkNCnN1bShpcy5uYShCTE0yMDIwJFRleHQpKQ0Kc3VtKGlzLm5hKEJMTTIwMjAkVHdlZXQuSWQpKQ0Kc3VtKGlzLm5hKEJMTTIwMjAkVXNlcm5hbWUpKQ0Kc3VtKGlzLm5hKEJMTTIwMjAkTG9jYXRpb24pKQ0Kc3VtKGlzLm5hKEJMTTIwMjAkTG9jYXRpb24pKQ0Kc3VtbWFyeShCTE0yMDIwKQ0Kc3VtbWFyeShCTE0yMDIwJExvY2F0aW9uKQ0KYGBgDQoNCipyZWdyZXNzaW9uIHJldHdlZXRzKg0KDQpgYGB7cn0NCnJldHdlZXRzX2dsbSA8LWdsbShSZXR3ZWV0IH4gLiwgZGF0YT1CTE0yMDIwKQ0KYGBgDQoNCipPbmUgd2F5IEFOT1ZBKg0KDQpgYGB7cn0NCiNyZW1vdmluZyBodG1sIHRhZ3MgZnJvbSB0aGUgc291cmNlX3R3ZWV0IHZhcmlhYmxlDQoNCmxpYnJhcnkodGV4dGNsZWFuKQ0KaHRtbF90YWdzIDwtIGMoDQogICAgIjxib2xkPlJhbmRvbTwvYm9sZD4gdGV4dCB3aXRoIHN5bWJvbHM6ICZuYnNwOyAmbHQ7ICZndDsgJmFtcDsgJnF1b3Q7ICZhcG9zOyIsDQogICAgIjxwPk1vcmUgdGV4dDwvcD4gJmNlbnQ7ICZwb3VuZDsgJnllbjsgJmV1cm87ICZjb3B5OyAmcmVnOyINCikNCg0KYmxtMjAyMCRzb3VyY2VfdHdlZXQ8LSByZXBsYWNlX2h0bWwoYmxtMjAyMCRzb3VyY2VfdHdlZXQpDQoNCg0KYGBgDQoNCipydW5uaW5nIHRoZSB0ZXN0Kg0KDQpgYGB7cn0NCiNjcmVhdGluZyBhIA0KDQpvbmUud2F5IDwtIGFvdihzb3VyY2VfdHdlZXQgfiAuLCBkYXRhID0gYmxtMjAyMCkNCg0KYGBgDQoNCg0KI0dyYXBocyBmb3IgZXZlcnkgdmFyaWFibGUgDQojR3JhcGggb24gdXNlciBhbW1vdW50IG9mIGZvbGxvd2Vycw0KI0NoZWNrIGlmIGEgdXNlciBoYXMgbWFkZSBtdWx0aXBsZSB0d2VldHMgLSBob3cgY2FuIHdlIGRvIHRoYXQ/IA0KI0ZpbHRlciBpZiBwYXJ0aWVzIGFyZSBtZW50aW9uZWQ=